package com.piggy.core.parser;

import com.alibaba.fastjson2.JSONObject;
import io.netty.buffer.ByteBuf;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class RequestParser {

    private final static Logger logger = LoggerFactory.getLogger(RequestParser.class);

    private final FullHttpRequest request;

    public RequestParser(FullHttpRequest request) {
        this.request = request;
    }

    /**
     * 简单处理请求路径
     */
    public String getUri() {
        String uri = request.uri();
        int idx = uri.indexOf("?");
        uri = idx > 0 ? uri.substring(0, idx) : uri;
//        if (uri.equals("/favicon.ico"))
        logger.info("uri -> {}", uri);
        return uri;
    }

    public JSONObject getParam() throws IOException {
        HttpMethod method = request.method();
        if (HttpMethod.GET == method || HttpMethod.DELETE == method) {
            QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
            Map<String, List<String>> parameters = decoder.parameters();
            return mapToJson(parameters);
        } else if (HttpMethod.POST == method || HttpMethod.PUT == method) {
            String contentType = getContentType();
            switch (contentType) {
                case "multipart/form-data":
                case "application/x-www-form-urlencoded":
                    HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(request);
                    List<InterfaceHttpData> bodyHttpData = decoder.getBodyHttpDatas();
                    Map<String, List<String>> parameters = new LinkedHashMap<>();
                    for(InterfaceHttpData data : bodyHttpData){
                        if(data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
                            Attribute attr = (Attribute) data;
                            String value = attr.getValue();
                            String name = attr.getName();
                            List<String> list = parameters.computeIfAbsent(name, k -> new ArrayList<>());
                            list.add(value);
                        }
                    }
                    return mapToJson(parameters);
                case "application/json":
                    ByteBuf byteBuf = request.content();
                    String content = byteBuf.toString(StandardCharsets.UTF_8);
                    return JSONObject.parseObject(content);
                case "none":
                    return new JSONObject();
                default:
                    throw new RuntimeException("未实现的协议类型 Content-Type：" + contentType);
            }
        }
        throw new RuntimeException("未实现的请求类型 HttpMethod：" + method);
    }

    private JSONObject mapToJson(Map<String, List<String>> parameters){
        JSONObject jsonObject = new JSONObject();
        Set<String> strings = parameters.keySet();
        for(String string : strings){
            List<String> list = parameters.get(string);
            if(list.size() == 1){
                jsonObject.put(string, list.get(0));
            }else{
                jsonObject.put(string, list);
            }
        }
        return jsonObject;
    }

    /*
     * POST /wg/activity/insert HTTP/1.1
     * Content-Type: application/json
     * User-Agent: PostmanRuntime/7.29.2
     * Postman-Token: xxx
     * Host: localhost:7397
     * Accept-Encoding: gzip, deflate, br
     * Connection: keep-alive
     * Content-Length: 45
     */
    private String getContentType() {
        Optional<Map.Entry<String, String>> header = request.headers().entries().stream().filter(
                val -> val.getKey().equals("Content-Type")
        ).findAny();
        Map.Entry<String, String> entry = header.orElse(null);
        if (null == entry)
            return "none";
        // application/json
        // multipart/form-data
        String contentType = entry.getValue();
        int idx = contentType.indexOf(";");
        if (idx > 0) {
            return contentType.substring(0, idx);
        } else {
            return contentType;
        }
    }

}
